using System.Collections.Generic;
using UnityEngine;

//Encoding：UTF-8
public interface IPlayer
{
    public void AllowAction(bool playPai, bool chi, bool peng, bool gang, bool anGang, bool jiaGang, bool ting, bool hu, bool ziMo, bool skip);
    public void SetAction(PlayerBase.Action action);
    public bool EqualsAction(PlayerBase.Action action);
    public void DrawOnStart(int[] ids);
    public void Draw(int id);
    public bool PlayPai();
    public void Peng();
    public void Gang();
    public void AnGang();
    public void JiaGang();
    public bool CanPeng();
    public bool CanGang();
    public bool CanAnGang();
    public bool CanJiaGang();
    public bool CanHu();
    public bool CanZiMo();
}

public class PlayerBase
{
    public enum Action
    {
        Non,
        Draw,
        PlayPai,
        Chi,
        Peng,
        Gang,
        AnGang,
        JiaGang,
        Ting,
        Hu,
        ZiMo,
        Skip
    }
    protected Action action;
    protected int playerID; // 当前玩家编号
    protected List<int> hand = new List<int>(); // 手牌
    protected List<List<int>> mingPai = new List<List<int>>(); // 桌面上的明牌
    protected List<int> anGangPaiID = new List<int>(); // 手牌中可以暗杠的牌id
    protected List<int> jiaGangPaiID = new List<int>(); // 手牌中可以加杠的牌id

    protected static (int, int) currentPlayPaiID; // 当前被打出的牌 playerID, paiID

    #region 执行摸牌、出牌、吃、碰、杠、暗杠、加杠、听、跳过操作
    public void SetAction(Action act)
    {
        action = act;
    }

    public bool EqualsAction(Action act)
    {
        return action == act;
    }

    public void DrawOnStart(int[] ids)
    {
        //抓起始手牌
        for (int i = 0; i < ids.Length; ++i)
        {
            hand.Add(ids[i]);
        }
        hand.Sort();
    }

    public void Draw(int id)
    {
        //抓牌
        hand.Add(id);
        hand.Sort();
    }

    public void PlayPai(int id)
    {
        //出牌
        hand.Remove(id);
        PaiOnTableController.singleton.ShowPaiOnTable(playerID, id);
        currentPlayPaiID = (playerID, id);
    }

    public void Chi()
    {
        //吃
    }

    public void Peng()
    {
        //碰
        hand.Remove(currentPlayPaiID.Item2);
        hand.Remove(currentPlayPaiID.Item2);
        mingPai.Add(new List<int>() { currentPlayPaiID.Item2, currentPlayPaiID.Item2, currentPlayPaiID.Item2 });
        PaiOnTableController.singleton.ShowMingPaiOnTable(playerID, mingPai[mingPai.Count - 1]);
        PaiOnTableController.singleton.HidePaiOnTable(currentPlayPaiID.Item1);
    }

    public void Gang()
    {
        //杠
        hand.RemoveAll(n => n == currentPlayPaiID.Item2);
        mingPai.Add(new List<int>() { currentPlayPaiID.Item2, currentPlayPaiID.Item2, currentPlayPaiID.Item2, currentPlayPaiID.Item2 });
        PaiOnTableController.singleton.ShowMingPaiOnTable(playerID, mingPai[mingPai.Count - 1]);
        PaiOnTableController.singleton.HidePaiOnTable(currentPlayPaiID.Item1);
    }

    public void AnGang()
    {
        //暗杠
        hand.RemoveAll(n => n == anGangPaiID[0]);
        mingPai.Add(new List<int>() { anGangPaiID[0], anGangPaiID[0], anGangPaiID[0], anGangPaiID[0] });
        PaiOnTableController.singleton.ShowMingPaiOnTable_AnGang(playerID);
    }

    public void JiaGang()
    {
        //加杠
        hand.RemoveAll(n => n == jiaGangPaiID[0]);
        for (int i = 0; i < mingPai.Count; ++i)
        {
            if (mingPai[i][0] == jiaGangPaiID[0])
            {
                mingPai[i].Add(jiaGangPaiID[0]);
            }
        }
        PaiOnTableController.singleton.ShowMingPaiOnTable_JiaGang(playerID, jiaGangPaiID[0]);
    }

    public void Ting()
    {
        //听
    }
    #endregion

    #region 判断能不能吃、碰、杠、暗杠、加杠、听、胡
    public void CanChi()
    {
        // 检测能不能吃
        //if (!PaiJuManager.singleton.canChi)
        //{
        //    return false;
        //}
        //int min = currentPlayPaiID.Item2 / 10 * 10;
        //int max = min + 10;
        //bool haveS2 = false;
        //bool haveS1 = false;
        //bool haveB1 = false;
        //bool haveB2 = false;
        //for (int i = 0; i < hand.Count; ++i)
        //{
        //    if (hand[i] > min && hand[i] < max)
        //    {
        //        if (hand[i] - currentPlayPaiID.Item2 == -2) haveS2 = true;
        //        if (hand[i] - currentPlayPaiID.Item2 == -1) haveS1 = true;
        //        if (hand[i] - currentPlayPaiID.Item2 == 1) haveB1 = true;
        //        if (hand[i] - currentPlayPaiID.Item2 == 2) haveB2 = true;
        //    }
        //}
        //if (haveS2 && haveS1) return true;
        //if (haveS1 && haveB1) return true;
        //if (haveB1 && haveB2) return true;
        //return false;
    }

    public bool CanPeng()
    {
        // 检测能不能碰
        int c = 0;
        for (int i = 0; i < hand.Count; ++i)
        {
            if (hand[i] == currentPlayPaiID.Item2)
            {
                ++c;
                if (c == 2) return true;
            }
        }
        return false;
    }

    public bool CanGang()
    {
        // 检测能不能杠
        int c = 0;
        for (int i = 0; i < hand.Count; ++i)
        {
            if (hand[i] == currentPlayPaiID.Item2)
            {
                ++c;
                if (c == 3) return true;
            }
        }
        return false;
    }

    public bool CanAnGang()
    {
        // 检测能不能暗杠
        for (int i = 0; i < hand.Count - 3; ++i)
        {
            if (hand[i] == hand[i + 1] && hand[i] == hand[i + 2] && hand[i] == hand[i + 3])
            {
                if (!anGangPaiID.Contains(hand[i])) anGangPaiID.Add(hand[i]);
            }
        }
        return anGangPaiID.Count != 0;
    }

    public bool CanJiaGang()
    {
        // 检测能不能加杠
        for (int i = 0; i < hand.Count; ++i)
        {
            for (int j = 0; j < mingPai.Count; ++j)
            {
                bool isJiaGang = true;
                for (int k = 0; k < mingPai[j].Count; ++k)
                {
                    if (mingPai[j][k] != hand[i])
                    {
                        isJiaGang = false;
                        break;
                    }
                }
                if (isJiaGang)
                {
                    if (!jiaGangPaiID.Contains(hand[i])) jiaGangPaiID.Add(hand[i]);
                }
            }
        }
        return jiaGangPaiID.Count != 0;
    }

    public void CanTing()
    {
        // 检测能不能听
    }

    public bool CanHu()
    {
        // 检测能不能胡
        List<int> pais = new List<int>(hand);
        pais.Add(currentPlayPaiID.Item2);
        pais.Sort();
        return CheckHu(pais);
    }

    public bool CanZiMo()
    {
        // 检测能不能自摸
        List<int> pais = new List<int>(hand);
        return CheckHu(pais);
    }

    List<int> checkedDuiZi = new List<int>(); // 已经检测过的对子
    private bool CheckHu(List<int> pais)
    {
        // 先检查是否是特殊牌型
        if (Check7DuiZi(pais))
        {
            return true;
        }
        if (Check13Yao(pais))
        {
            return true;
        }

        // 再检查通常牌型
        checkedDuiZi.Clear();
        for (int i = 0; i < pais.Count - 1; ++i)
        {
            if (!checkedDuiZi.Contains(pais[i])) // 跳过已经检测过的对子
            {
                if (pais[i] == pais[i + 1])
                {
                    checkedDuiZi.Add(pais[i]);
                    List<int> paisTemp = new List<int>(pais);
                    paisTemp.RemoveAt(i);
                    paisTemp.RemoveAt(i);
                    List<int> paisTemp1 = new List<int>(paisTemp);
                    /*
                     * 检测顺序，只要有一条路径返回True就说明能胡牌
                     * 优先检查刻子，若没有刻子或者是此刻子的组合不能胡牌，则检查顺子
                     * - 刻子 - 刻子 - 刻子 - 刻子
                     * |     |      |      |
                     * |     |      |      - 顺子
                     * |     |      - 顺子 - 顺子
                     * |     - 顺子 - 顺子 - 顺子
                     * - 顺子 - 顺子 - 顺子 - 顺子
                     */
                    if (FindKeZi(paisTemp))
                    {
                        return true;
                    }
                    if (FindShunZi(paisTemp1))
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private bool Check7DuiZi(List<int> pais)
    {
        // 检查七对子
        if (pais.Count != 14) return false;

        for (int i = 0; i < pais.Count - 1; i += 2)
        {
            if (pais[i] != pais[i + 1])
            {
                return false;
            }
        }
        return true;
    }

    int[] _13Yao = new int[] { 1, 2, 3, 4, 5, 6, 7, 11, 19, 21, 29, 31, 39 };
    private bool Check13Yao(List<int> pais)
    {
        // 检查十三幺，对应编号为1，2，3，4，5，6，7，11，19，21，29，31，39
        if (pais.Count != 14) return false;

        int idx = 0;
        for (int i = 0; i < pais.Count - 1; ++i)
        {
            if (pais[i] == pais[i + 1])
            {
                continue;
            }
            if (pais[i] != _13Yao[idx])
            {
                return false;
            }
            ++idx;
        }
        if (pais[pais.Count - 1] != _13Yao[12])
        {
            return false;
        }
        return true;
    }

    private bool FindKeZi(List<int> pais)
    {
        // 查找牌中的刻子
        if (pais.Count == 0)
        {
            return true;
        }
        for (int i = 0; i < pais.Count - 2; ++i)
        {
            if (pais[i] == pais[i + 1] && pais[i] == pais[i + 2])
            {
                pais.RemoveAt(i);
                pais.RemoveAt(i);
                pais.RemoveAt(i);
                List<int> paisTemp = new List<int>(pais);
                if (FindKeZi(pais))
                {
                    return true;
                }
                if (FindShunZi(paisTemp))
                {
                    return true;
                }
            }
        }
        return false;
    }

    private bool FindShunZi(List<int> pais)
    {
        // 查找牌中的顺子
        if (pais.Count == 0)
        {
            return true;
        }
        for (int i = 0; i < pais.Count - 2; ++i)
        {
            if (pais[i] > 10 && (pais[i] + 1) == pais[i + 1] && (pais[i] + 2) == pais[i + 2])
            {
                pais.RemoveAt(i);
                pais.RemoveAt(i);
                pais.RemoveAt(i);
                if (FindShunZi(pais))
                {
                    return true;
                }
            }
        }
        return false;
    }
    #endregion
}
